<?php
# base class for pdo-based daos
# encapsulates helping methods
abstract class DaoAbstract {
	
	# query templates
	# mysql specific syntax, combines update & insert in one db call
	const SAVE_TEMPLATE =
		"INSERT INTO <table> (<columns>) VALUES (<values>) ON DUPLICATE KEY UPDATE <update>";

	const DELETE_TEMPLATE =
		"DELETE FROM <table> WHERE <column> = <value>";
	
	# fill templates with parameters
	protected static function applySave($table,$columns) {
		$search = array("<table>","<columns>","<values>","<update>");
		$columnList = implode(",",$columns);
		$placeHolderList = implode(",",array_map(function($x) { return ":".$x; }, $columns));
		$updateList = implode(",",array_map(function($x) { return $x." = VALUES(".$x.")"; }, $columns));
		return str_replace($search, array($table,$columnList,$placeHolderList,$updateList),self::SAVE_TEMPLATE); 
	}
	
	protected static function applyDelete($table,$key) {
		$search = array("<table>","<column>","<value>");
		$replace = array($table,$key,":".$key);
		return str_replace($search,$replace,self::DELETE_TEMPLATE);
	}
	
	# constructor takes PDO connection
	private $conn;
	
	public function __construct($conn) {
		$this->conn = $conn;
	}
	# frees PDO connection
	public function dispose() {
		$this->conn = null;
	}
	
	# dao support methods 
	protected function conn() {
		return $this->conn;
	}
	# executes select and fetches first result row
	protected function single($sql,$params = array()) {
		try {
			$stmt = $this->exec($sql, $params);
			$result = $stmt->fetch(); 
			$stmt->closeCursor();	# make sure unfetched rows do not block
		} catch (PDOException $e) {
			echo "!! dao failure on single fetch :".$e->getMessage()."\n";
			throw $e;
		}
		return $result;
	}
	# executes select and fetches all result rows
	protected function multiple($sql,$params = array()) {
		try {
			$stmt = $this->exec($sql,$params);
			$result = $stmt->fetchAll();
		} catch (PDOException $e) {
			echo "!! dao failure on multi fetch :".$e->getMessage()."\n";
			throw $e;
		}
		return $result;
	}
	# executes any query and returns result set
	protected function exec($sql,$params = array()) {
		#echo "executing ".$sql." with \n";  print_r($params);
		$stmt = $this->conn()->prepare($sql);
		foreach ($params as $key => &$value) {
			$stmt->bindParam($key,$value);
		}
		$stmt->setFetchMode(PDO::FETCH_ASSOC);
		#$stmt->debugDumpParams();
		$stmt->execute();
		return $stmt;
	}
	
	# extracts all parameters with key in $params from $src associative array 
	protected function extractParams($src,$params) {
		$result = array();
		foreach($params as $currParam) {
			$result[$currParam] = $src[$currParam];
		}
		return $result;
	}
}
?>